package com.module.third.ext

import androidx.lifecycle.viewModelScope
import com.module.frame.retrofit.BaseResponse
import com.module.frame.base.BaseFrameViewModel
import com.module.frame.ext.postEvent
import kotlinx.coroutines.*

/**
 * 超时时间
 */
private const val TIMEOUT_TIME: Long = 30000

/**
 * //请求成功失败返回 直接返回BaseResponse
 * @param block 请求体方法
 * @param isShowDialog 是否显示加载框
 * @param sucResult 请求成功
 * @param failResult 请求失败
 * @param timeMillis 超时时间
 */
internal fun <T> BaseFrameViewModel.request(
    block: suspend () -> BaseResponse<T>,
    sucResult: (T?) -> Unit,
    failResult: (String) -> Unit,
    isShowDialog: Boolean = false,
    timeMillis: Long = TIMEOUT_TIME,//默认超时20s
): Job {
    return viewModelScope.launch(Dispatchers.Main) {
        try {
            var it: BaseResponse<T>
            if (isShowDialog) postEvent(loadDialogShareFlow, true)
            withTimeout(timeMillis) {
                //请求体
                it = block()
            }
            //成功处理
            postEvent(loadDialogShareFlow, false)
            if (it.isSuccess()) {
                sucResult(it.getData())
            } else {
                //处理异常
                isDealException(it.getMsg(), it.getCode())?.apply {
                    failResult(this)
                }
            }
        } catch (it: Exception) {
            postEvent(loadDialogShareFlow, false)
            //处理异常
            isDealException(it)?.apply {
                failResult(this)
            }
        }
    }
}

/**
 * //请求成功失败返回 直接返回数据
 * @param block 请求体方法
 * @param isShowDialog 是否显示加载框
 * @param sucResult 请求成功
 * @param failResult 请求失败
 * @param timeMillis 超时时间
 */
internal fun <T> BaseFrameViewModel.request2(
    block: suspend () -> T,
    sucResult: (T?) -> Unit,
    failResult: (String) -> Unit,
    isShowDialog: Boolean = false,
    timeMillis: Long = TIMEOUT_TIME,//默认超时20s
): Job {
    return viewModelScope.launch(Dispatchers.Main) {
        try {
            var it: T
            if (isShowDialog) postEvent(loadDialogShareFlow, true)
            withTimeout(timeMillis) {
                //请求体
                it = block()
            }
            //成功处理
            postEvent(loadDialogShareFlow, false)
            sucResult(it)
        } catch (it: Exception) {
            postEvent(loadDialogShareFlow, false)
            //处理异常
            isDealException(it)?.apply {
                failResult(this)
            }
        }
    }
}

/**
 * 报错重试
 * @param maxRetries 最高重试几次，不包含第一次请求
 * @param retryDelayMillis 重试等待时间
 */
internal suspend fun <T> retry(
    maxRetries: Int,
    retryDelayMillis: Long,
    block: suspend () -> T
): T {
    return try {
        block()
    } catch (e: Exception) {
        if (maxRetries > 0) {
            //延迟时间
            delay(retryDelayMillis)
            //重新调用
            retry(maxRetries - 1, retryDelayMillis, block)
        } else {
            throw e
        }
    }
}

private fun isDealException(message: String?, code: Int): String? {
    if (!isDeal(Throwable(message))) {
        return null
    }
    return message
}

private fun isDealException(e: Throwable): String? {
    if (!isDeal(e)) {
        return null
    }
    return e.message
}


/**
 * 异常处理
 */
private fun isDeal(e: Throwable): Boolean {
    var isDeal = true
    when (e) {
        is IllegalStateException -> {
            when {
                e.message?.equals("Job was cancelled") == true -> {
                    //由于JobCancellationException无法使用，所以只能判断Job was cancelled
                    //Job 的生命周期结束取消 所以不回调用，避免错误
                    isDeal = false;
                }

            }

        }
    }
    return isDeal
}

